All prerequisites, links to material and slides for this course can be found on github.
Or can be downloaded as a zip archive from here.
Once the zip file in unarchived. All presentations as HTML slides and pages, their R code and HTML practical sheets will be available in the directories underneath.
Before running any of the code in the practicals or slides we need to set the working directory to the folder we unarchived.
You may navigate to the unarchived RU_Course_help folder in the Rstudio menu.
Session -> Set Working Directory -> Choose Directory
or in the console.
A shiny app consists of the user interface (UI) and the server function * the UI object defines what will be seen on the page * the server function contains code that combines R code with inputs (eg info from user, databases, or files) and provides instructions for generating outputs * the shinyApp function builds the shiny app from the the UI object and server function
Neth, H. (2025) Introduction to Data Science (https://bookdown.org/hneth/i2ds/)
A Shiny app is generally contained within one R script to define the UI object and the server function.
library(shiny)
library(bslib)
ui = page_fluid(
textOutput(outputId = "app_info")
)
server = function(input, output) {
output$app_info = renderText("Our first app!")
}
shinyApp(ui = ui, server = server)When you run the shinyApp function, your RStudio console will be busy and you’ll see a message with a URL. This is the port within your computer that the app is running.
A window should pop up automatically showing the app. You can also copy and paste this address into a browser to open an instance of the app.
To close the app and free up the console, you can: * click on the console to hit the ESC button or Ctrl+C * click on the Stop button on the top right corner of the console
Pretty much any Shiny app will start with the code below. Just paste this code into a fresh R script to get started.
TIP: Open a new R script, type shinyapp, then hit Shift+Tab, and the template will appear.
Boiler plate Shiny app code:
Shiny is well integrated into R Studio and there are a few additional features that make running apps easier.
If you open a blank R script and add the shiny template code (see previous slide), once you save the file you should see a button in the upper right corner of the script that says Run App.
This will automatically launch the app.
How that app is launched (e.g. in browser or a window within RStudio) can be changed by the dropdown that is part of the Run App button
You can also start a new app by opening a new file in R Studio and selecting the Shiny Web App option.
The Application name you enter will be the name of a newly created directory that contains the app.R file and your Shiny app.
]
]
The Shiny cheatsheet is a great resource demonstrating built-in input and output options
ADD IMAGE OF INPUTS FREOM CHEATSHEET!
or go through inputs like mastering shiny book
or go through the posit widget gallery
Talk about outputs and how outputs are paired with render functions
## [1] "<div class=\"container-fluid\">\n <div id=\"app_info\" class=\"shiny-text-output\"></div>\n</div>"
server function and launch app
Global variables can be assigned in the script outside of the UI object and server function. This code is run once upon initiating the app and global variables and settings are available within the app.
# read in table
de_table <- read.csv("data/shP53_vs_control_DEG.csv")
de_table$negLog10_pval <- -log10(de_table$pvalue)
# view table (would not be part of shiny script)
head(de_table, 3)## ID Symbol baseMean log2FoldChange lfcSE stat pvalue
## 1 ENSG00000002745 WNT16 1531.822 -3.766480 0.08955896 -42.05587 0
## 2 ENSG00000026025 VIM 1578.109 5.556894 0.12318261 45.11103 0
## 3 ENSG00000104419 NDRG1 6651.576 -3.614629 0.07273378 -49.69671 0
## padj negLog10_pval
## 1 0 Inf
## 2 0 Inf
## 3 0 Inf
We are going to use the DT package to show the table in our app. This provides a very interactive table out of the box with little extra work.
We add the table using the dataTableOutput function in the UI, which is paired with the renderDataTable function in the server.
library(DT)
ui_simple = page_fluid(
textOutput(outputId = "app_info"),
DT::dataTableOutput(outputId = "de_data") #<<
)
server_simple = function(input, output) {
output$app_info = renderText("This is an app showing differential gene expression data")
output$de_data = renderDataTable(datatable(de_table)) #<<
}The DT package allows for a lot of customization of the html datatable. This link shows some of the capabilities.
Below we will add custom filters on top of each column and round the values to improve the appearance.
server_simple2 = function(input, output) {
output$app_info = renderText("This is an app showing differential gene expression data")
output$de_data = renderDataTable({
datatable(de_table, #<<
filter = 'top') %>% #<<
formatRound(columns = c("baseMean", "log2FoldChange", "lfcSE", "stat"), digits = 3) %>% #<<
formatSignif(columns = c("pvalue", "padj"), digits = 3) #<<
})
}Add an MA plot and a Volcano plot to the page. First add the outputs to the UI object
Then make the server function containing the render functions that tell shiny how to make the outputs from the IU object.
server_data = function(input, output) {
output$app_info = renderText("This is an app showing differential gene expression data")
output$de_data = renderDataTable({
datatable(de_table,filter = 'top') %>%
formatRound(columns = c("baseMean", "log2FoldChange", "lfcSE", "stat"), digits = 3) %>%
formatSignif(columns = c("pvalue", "padj"), digits = 3)
})
output$ma_plot = renderPlot({ #<<
ggplot(de_table, aes(x = baseMean, y = log2FoldChange)) + geom_point() + #<<
scale_x_log10() + xlab("baseMean (log scale)") + theme_bw()#<<
}) #<<
output$volcano_plot = renderPlot({ #<<
ggplot(de_table, aes(x = log2FoldChange, y = negLog10_pval)) + geom_point() + theme_bw() #<<
}) #<<
} bslib has many functions that allow customizing the formatting of the page. Here we add ‘cards’, which are boxes that allow grouping of UI components
We can add the ability to hide certain boxes with accordions from the bslib package. By default only the top accordion is open, but the accordian function has an argument ‘open’ that allows you to select which are when the app is started.
The ‘col_widths’ argument of the layout_columns function will control with width of the column. The bootstrap grid system is made up of 12 columns. A numeric vector is provided with widths for each card. Once the elements combined width goes above 12, then the elements are wrapped to the next row.
More complicated layouts can be achieved by nesting layout_columns functions. Here we add a tall card as a new row below the table and then nest the plots within this row next to the card.
ui_nested <- page_fillable(
layout_columns(
col_widths = 12,
card(card_header("Table of DE results", dataTableOutput(outputId = "de_data")))),
layout_columns(
col_widths = 6,
card(card_header("This is a tall box")),
layout_columns(
col_widths = c(12,12),
card(card_header("MA plot",plotOutput("ma_plot"))),
card(card_header("Volcano plot",plotOutput("volcano_plot")))
)
),
)While we have been using the page_fillable function to build the UI, there are three main functions from bslib for slightly differnet page layout strategies:
Image from the Posit tutorials (https://shiny.posit.co/r/articles/build/layout-guide/)
The cards do not fill the screen horizontally and dynamically, but when the window is not big enough, the cards ajust and add scroll bars so you have access to the whole table or plot not matter what.
The cards do not fill the screen horizontally as there is padding on each side and the cards are a fixed height. When the window is not big enough, you need to scroll down to see the plots on the bottom of the page.
It’s easy to modify the look of the app using the bslib package. The page_sidebar function (and other payout functions) has a ‘theme’ argument that takes a bs_theme object.
bslib has builtin themes that can be easily used. The themes can be previewed (here)[https://bootswatch.com/], and the string to use in the ‘bootswatch argument’ of the bs_theme function can be picked from the vector returned by bootswatch_themes()
## [1] "cerulean" "cosmo" "cyborg" "darkly" "flatly" "journal"
## [7] "litera" "lumen" "lux" "materia" "minty" "morph"
## [13] "pulse" "quartz" "sandstone" "simplex" "sketchy" "slate"
## [19] "solar" "spacelab" "superhero" "united" "vapor" "yeti"
## [25] "zephyr"
ui_cerulean <- page_navbar(
title = "RNAseq tools",
theme = bs_theme(version = 5, bootswatch = "cerulean"), #<<
nav_panel(
title = "DE Analysis",
layout_sidebar(
sidebar = sidebar("This is a sidebar", width = 300),
layout_columns(
card(card_header("Table of DE results"), dataTableOutput(outputId = "de_data")),
card(card_header("MA plot"),plotOutput("ma_plot")),
card(card_header("Volcano plot"),plotOutput("volcano_plot")),
col_widths = c(12,6,6), row_heights = c("750px", "500px")
)
)
),
nav_panel(title = "Next steps","The next step in our analysis will be..."),
nav_spacer(),
nav_menu(title = "Links",
align = "right",
nav_item(tags$a(shiny::icon("chart-simple"), "RU BRC - Learn more!", href = "https://rockefelleruniversity.github.io/",target = "_blank"))
)
)ui_darkly <- page_navbar(
title = "RNAseq tools",
theme = bs_theme(version = 5, bootswatch = "darkly"), #<<
nav_panel(
title = "DE Analysis",
layout_sidebar(
sidebar = sidebar("This is a sidebar", width = 300),
layout_columns(
card(card_header("Table of DE results"), dataTableOutput(outputId = "de_data")),
card(card_header("MA plot"),plotOutput("ma_plot")),
card(card_header("Volcano plot"),plotOutput("volcano_plot")),
col_widths = c(12,6,6), row_heights = c("750px", "500px")
)
)
),
nav_panel(title = "Next steps","The next step in our analysis will be..."),
nav_spacer(),
nav_menu(title = "Links",
align = "right",
nav_item(tags$a(shiny::icon("chart-simple"), "RU BRC - Learn more!", href = "https://rockefelleruniversity.github.io/",target = "_blank"))
)
)A big benefit of the bs_theme function is the ability to highly customize the app theme. This can be done with the arguments to the function, or with additional CSS. We use custom CSS to modify the header of the cards throughout the app and manually set the main color options.
custom_css <- "
.card-header {
background-color: #d3dff1;
border-bottom: 2px solid #273449;
}
"
# Create theme with custom CSS
custom_theme <- bs_theme(
version = 5,
bg = "white",
fg = "#273449",
primary = "#5886b2",
secondary = "#95a5a6",
success = "#18bc9c",
info = "#3498db",
warning = "#f39c12",
danger = "#e74c3c",
preset = "bootstrap",
"navbar-bg" = "#5886b2"
) |> bs_add_rules(custom_css)This custom theme object can then be used in the ‘theme’ argument of page_sidebar.
ui_custom <- page_navbar(
title = "RNAseq tools",
theme = custom_theme, #<<
nav_panel(
title = "DE Analysis",
layout_sidebar(
sidebar = sidebar("This is a sidebar", width = 300),
layout_columns(
card(card_header("Table of DE results"), dataTableOutput(outputId = "de_data")),
card(card_header("MA plot"),plotOutput("ma_plot")),
card(card_header("Volcano plot"),plotOutput("volcano_plot")),
col_widths = c(12,6,6), row_heights = c("750px", "500px")
)
)
),
nav_panel(title = "Next steps","The next step in our analysis will be..."),
nav_spacer(),
nav_menu(title = "Links",
align = "right",
nav_item(tags$a(shiny::icon("chart-simple"), "RU BRC - Learn more!", href = "https://rockefelleruniversity.github.io/",target = "_blank"))
)
)Exercises for Session 1 are here